Import necessary modules¶

In [1]:
import pathlib

from ipyniivue import download_dataset

DATA_FOLDER = pathlib.Path("images")

download_dataset(
    api_url="https://niivue.com/demos/images/",
    dest_folder=DATA_FOLDER,
    files=[
        "example4d+orig.HEAD",
        "example4d+orig.BRIK.gz",
    ],
)
Downloading example4d+orig.HEAD...
Downloading example4d+orig.BRIK.gz...
Dataset downloaded successfully to images.
In [2]:
import asyncio

import ipywidgets as widgets
from IPython.display import display

from ipyniivue import NiiVue, ShowRender, SliceType

# Create the NiiVue widget

nv = NiiVue()

nv.set_radiological_convention(False)
nv.set_slice_type(SliceType.MULTIPLANAR)
nv.opts.multiplanar_show_render = ShowRender.ALWAYS

# Configure graph values
nv.graph.auto_size_multiplanar = True
nv.graph.normalize_values = False
nv.graph.opacity = 1.0

# Load 4D volume with paired HEAD and BRIK files
nv.load_volumes(
    [
        {
            "path": DATA_FOLDER / "example4d+orig.HEAD",
            "paired_img_path": DATA_FOLDER / "example4d+orig.BRIK.gz",
            "colormap": "gray",
            "opacity": 1.0,
        },
    ]
)

# Create other buttons/checkboxes

display_frame = widgets.Label(value="Volume: 0")

normalize_checkbox = widgets.Checkbox(
    value=False,
    description="Normalize Graph",
)

prev_button = widgets.Button(description="Back")
next_button = widgets.Button(description="Forward")

# Implement the callbacks


def on_normalize_change(change):
    """Normalize graph."""
    nv.graph.normalize_values = change["new"]


normalize_checkbox.observe(on_normalize_change, names="value")


def on_prev_button_clicked(b):
    """Decrement the frame index."""
    if nv.volumes:
        current_frame = nv.volumes[0].frame_4d
        new_frame = max(current_frame - 1, 0)
        nv.volumes[0].frame_4d = new_frame
        display_frame.value = f"Volume: {new_frame}"


def on_next_button_clicked(b):
    """Increment the frame index."""
    if nv.volumes:
        current_frame = nv.volumes[0].frame_4d
        n_frames = nv.volumes[0].n_frame_4d
        new_frame = min(current_frame + 1, n_frames - 1)
        nv.volumes[0].frame_4d = new_frame
        display_frame.value = f"Volume: {new_frame}"


prev_button.on_click(on_prev_button_clicked)
next_button.on_click(on_next_button_clicked)

# Create animate button

animate_button = widgets.Button(description="Animate")

animation_running = False
animation_task = None


async def animate_frames():
    """Animation loop."""
    global animation_running
    if not nv.volumes:
        return
    n_frames = nv.volumes[0].n_frame_4d
    try:
        while animation_running:
            current_frame = nv.volumes[0].frame_4d
            current_frame = (current_frame + 1) % n_frames
            nv.volumes[0].frame_4d = current_frame
            display_frame.value = f"Volume: {current_frame}"
            await asyncio.sleep(0.1)
    except asyncio.CancelledError:
        pass


def on_animate_button_clicked(b):
    """Define 'Animate' button click handler."""
    global animation_running, animation_task
    if not animation_running:
        # Start animation
        animation_running = True
        animate_button.description = "Stop"
        # Schedule the animation coroutine and store the future
        animation_task = asyncio.ensure_future(animate_frames())
    else:
        # Stop animation
        animation_running = False
        animate_button.description = "Animate"
        # Cancel the running task if it's active
        if animation_task is not None:
            animation_task.cancel()
            animation_task = None


animate_button.on_click(on_animate_button_clicked)

# Reset frame index on image loaded


@nv.on_image_loaded
def update_number_of_frames(volume):
    """Reset to first frame."""
    nv.volumes[0].frame_4d = 0
    display_frame.value = "Volume: 0"


# Display all

controls = widgets.HBox(
    [
        normalize_checkbox,
        prev_button,
        next_button,
        animate_button,
    ]
)

display(widgets.VBox([controls, display_frame, nv]))